package gaileenchess;

import java.util.Scanner;
import java.util.LinkedList;

public class Main
{
    private enum State {IDLE, INGAME}; // game state. Only has 2 states now, but may need to add more later
    public static Scanner in;
    
    public static void main(String[] args)
    {
        History history = new History();
        
        in = new Scanner(System.in);
        Player player[] = new Player[2]; // 2 players - can be either human or computer
        
        int turn = 0; // keeps track of whose turn it is (player[0] or player[1])
        Command command; // this keep track of the player's commands, returned by Player.getCommand()
        Board board = new Board(); // this is our main board, we should only have one of these
        boolean nextTurn = true; // some commands don't require that we change it to the next player's turn. By default we will though.
        boolean confirm = true;
        boolean currentPlayerCheck = false;
        State state = State.INGAME; // current game state - automatically start new game at the beginning
        board.reset(); // reset the pieces on our board by default, can also be done by "new" command
        
        // initializing 2 players, right now just to human, later we'll let user decide what kind of player
        player[0] = new HumanPlayer(Common.Side.WHITE, board);
        player[1] = new HumanPlayer(Common.Side.BLACK, board);
        
        // add the players to the board - required for things like check
        board.addPlayers(player);
        
        // main game loop, as long as the program is running, in-game or waiting for input, we should be in here
        while(true)
        {
            // things we need to do iff it's the next player's turn (ie the previous player just finished a move)
            //   like check, history (mostly for threefold repetition), check for gameover, user prompt, etc
            if(state == State.INGAME && nextTurn)
            {
                currentPlayerCheck = board.isInCheck(turn);
                if(board.isGameOver(turn, currentPlayerCheck))
                {
                    if(currentPlayerCheck)
                    {
                        System.out.println("Check mate, player " + player[turn].getSideString() + " loses");//TODO
                    }
                    else
                    {
                        System.out.println("Stale mate");
                    }
                    state = State.IDLE;
                }
                // checks for threefold repetition
                else if(history.add(board, player) >= 3)
                {
                    System.out.println("Stale mate - threefold repetition");
                    state = State.IDLE;
                }
                else
                {
                    // we want to print this iff the previous command caused us to switch users (TODO: print this anyway??)
                    System.out.println("PLayer " + player[turn].getSideString() + ", please enter a command:");

                    //check
                    if(board.isInCheck(turn))
                    {
                        System.out.println("CHECK");
                    }
                }
            }
            else if(state != State.INGAME)
            {
                System.out.println("Please enter a command:");
            }
            command = player[turn].getCommand();
            nextTurn = true; // true by default for the coming command
            
            // this basically handles what to do now that our commands have been retrieved and parsed
            switch(command.type)
            {
                // new game
                case NEW:
                if(state == State.INGAME)
                {
                    confirm = player[turn].confirm();
                }
                if(confirm)
                {
                    // TODO: new game message?
                    turn = 1;
                    state = State.INGAME;
                    board.reset();
                    player[0].reset(board);
                    player[1].reset(board);
                    history.reset();
                }
                else
                {
                    nextTurn = false;
                }
                break;

                // quit the program
                case QUIT:
                if(state == State.INGAME)
                {
                    confirm = player[turn].confirm();
                }
                else
                {
                    confirm = true;
                }
                if(confirm)
                {
                    System.exit(0);
                }
                else
                {
                    nextTurn = false;
                }
                break;
                
                // forfeit game (doesn't imply quitting the program)
                case FORFEIT:
                if(state == State.INGAME)
                {
                    //TODO
                    confirm = player[turn].confirm();
                    if(confirm)
                    {
                        state = State.IDLE;
                    }
                    else
                    {
                        nextTurn = false;
                    }
                }
                else
                {
                    System.out.println("This command is only available when you are in a game. Type \"help\" for help.");
                    nextTurn = false;
                }
                break;
                
                // move a piece (or tell the user if it's an illegal move)
                case MOVE:
                if(state == State.INGAME && board.isValidMove(turn, command.args[0], command.args[1]))
                {
                    board.move(command.args[0], command.args[1], true, turn);
                }
                else if(state == State.INGAME)
                {
                    System.out.println("Illegal move. Please try again."); // TODO: more helpful?
                    nextTurn = false;
                }
                else
                {
                    System.out.println("This command is only available when you are in a game. Type \"help\" for help.");
                    nextTurn = false;
                }
                break;
                
                // display the current board and where pieces are on the command-line
                case DISPLAY:
                if(state == State.INGAME)
                {
                    nextTurn = false;
                    board.display();
                }
                else
                {
                    System.out.println("This command is only available when you are in a game. Type \"help\" for help.");
                    nextTurn = false;
                }
                break;
                
                // output a command reference
                case HELP:
                nextTurn = false;
                Command.displayHelp();
                break;
                
                // accept custom board configuration
                case SETUP:
                if(state == State.INGAME)
                {
                    confirm = player[turn].confirm();
                }
                else
                {
                    confirm = true;
                }
                if(confirm)
                {
                    // TODO: new game message?

                    Piece[][] boardConfig = player[turn].getSetup();

                    if(boardConfig != null)
                    {
                        Board newboard = new Board(boardConfig);
                        Player p[] = new Player[2];
                        p[0] = player[0].newP(newboard);
                        p[1] = player[1].newP(newboard);
                        newboard.addPlayers(p);

                        if(newboard.isValid())
                        {
                            board = newboard;
                            history.reset();
                            player = p;
                            turn = 1;
                            state = State.INGAME;
                        }
                        else
                        {
                            System.out.println("Invalid Configuration.");
                            nextTurn = false;
                        }
                    }
                    else
                    {
                        nextTurn = false;
                    }
                }
                else
                {
                    nextTurn = false;
                }
                
                break;
                
                // display a list of valid moves for the given piece
                case VALID:
                nextTurn = false;
                if(state == State.INGAME)
                {
                    Piece p = board.getPiece(command.args[0]);
                    Common.Side playerSide = player[turn].getSide();
                    
                    if(p != null && p.getSide() == playerSide)
                    {
                        LinkedList<Board.Position.Move> validMoves = new LinkedList<Board.Position.Move>();
                        p.getValidMoves(playerSide, board, validMoves, currentPlayerCheck, turn);
                        for(Board.Position.Move m : validMoves)
                        {
                            System.out.println(m.destToString());
                        }
                    }
                    else
                    {
                        System.out.println("Invalid Piece.");
                    }
                }
                else
                {
                    System.out.println("This command is only available when you are in a game. Type \"help\" for help.");
                }
                break;
                
                // use computer AI to suggest a next move
                case HINT:
                nextTurn = false;
                if(state == State.INGAME)
                {
                    //TODO
                }
                else
                {
                    System.out.println("This command is only available when you are in a game. Type \"help\" for help.");
                    nextTurn = false;
                }
                break;
                
                // this is for the case where the user's command wasn't a real command (or their arguments were malformed)
                case INVALID:
                default:
                nextTurn = false;
                System.out.println("Unrecognized command. For help, please type \"help\"");
                break;
            }
            
            if(nextTurn)
            {
                turn = (turn + 1) % 2; // next player's turn
            }
        }
    }
}
